#include "DVRCommonPCH.h"
#include "LoadVolume.h"

using namespace hiveDVR;

//**************************************************************************************************
//FUNCTION:
CVolume::CVolume()
{
	m_pHeader = new hiveDVR::SVolumeInfo;
}

//**************************************************************************************************
//FUNCTION:
CVolume::~CVolume()
{
	SAFE_DELETE(m_pHeader);
}

//**************************************************************************************************
//FUNCTION:
bool CVolume::loadHeader(const std::string& vFileHeader)
{
	if (vFileHeader.empty()) return outputWarning(__EXCEPTION_SITE__, "Empty header file name.");
	SAFE_DELETE(m_pHeader);
	m_pHeader = new hiveDVR::SVolumeInfo;

	std::ifstream FileStream(vFileHeader);
	if (!FileStream) return outputWarning(__EXCEPTION_SITE__, "The file opening failed, please check the file name!");
	std::string Line;

	std::getline(FileStream, Line);
	std::istringstream ss(Line);
	ss >> m_pHeader->Extents;
	m_VolumeAABB = { glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(getWidth(), getHeight(), getDepth()) };

	std::getline(FileStream, Line);
	ss = std::istringstream(Line);
	ss >> m_pHeader->VoxelSize;

	std::getline(FileStream, Line);
	ss = std::istringstream(Line);
	ss >> m_pHeader->NormalisationRange;

	std::getline(FileStream, Line);
	ss = std::istringstream(Line);
	ss >> m_pHeader->Type >> m_pHeader->Endianness;

	std::getline(FileStream, Line);
	ss = std::istringstream(Line);
	glm::vec4 AngleAxis(0);
	ss >> AngleAxis;

	FileStream.close();

	convert2RawFileName(vFileHeader, m_pHeader->Directory, m_pHeader->VolumeName);

	glm::vec3 PhysicalSize = m_pHeader->VoxelSize * glm::vec3(m_pHeader->Extents);
	m_pHeader->ImageTransform = glm::rotate(glm::radians(AngleAxis.w), glm::vec3(AngleAxis)) * glm::scale(PhysicalSize);

	return __loadData();
}

//**************************************************************************************************
//FUNCTION:
bool CVolume::__loadData()
{
	_ASSERTE(m_pHeader);
	bool Result = false;

	if (m_pHeader->Type == "uint8_t")
	{
		Result = __loadDataImpl<uint8_t>(m_pHeader, m_ScalarSet);
	}
	else if (m_pHeader->Type == "int8_t")
	{
		Result = __loadDataImpl<int8_t>(m_pHeader, m_ScalarSet);
	}
	else if (m_pHeader->Type == "uint16_t")
	{
		Result = __loadDataImpl<uint16_t>(m_pHeader, m_ScalarSet);
	}
	else if (m_pHeader->Type == "int16_t")
	{
		Result = __loadDataImpl<int16_t>(m_pHeader, m_ScalarSet);
	}
	else
	{
		return outputWarning(__EXCEPTION_SITE__, "Unsupported image data type: <" + m_pHeader->Type + ">.");
	}

	m_MaxScalar = std::numeric_limits<uint8_t>::max();

	return Result ? true : outputWarning(__EXCEPTION_SITE__, "Fail to load volume data from file: <" + m_pHeader->Directory + m_pHeader->VolumeName + ">.");
}

//**************************************************************************************************
//FUNCTION:
float CVolume::sampleAverageData(CAABB& vAABB) const
{
	CAABB SampleBoundingBox = m_VolumeAABB.intersect(vAABB.scale(m_VolumeAABB.getMax()));

	float Sum = 0.0f;
	int Count = 0;

	for (size_t x = SampleBoundingBox.getMin().x; x < SampleBoundingBox.getMax().x; ++x)
	{
		for (size_t y = SampleBoundingBox.getMin().y; y < SampleBoundingBox.getMax().y; ++y)
		{
			for (size_t z = SampleBoundingBox.getMin().z; z < SampleBoundingBox.getMax().z; ++z)
			{
				size_t Index = z * getWidth() * getHeight() + y * getWidth() + x;
				Sum += static_cast<float>(m_ScalarSet[Index]) / static_cast<float>(m_MaxScalar);
				++Count;
			}
		}
	}

	return Sum / Count;
}